#ifndef CONFIGURATION_H
#define CONFIGURATION_H

#include <iostream>
#include "vector"

#include "ngl/Camera.h"
#include "ngl/SpotLight.h"
#include "ngl/Colour.h"

#include "ShaderObject.h"
#include "Particle.h"
#include "FluidParticle.h"
#include "Capsule.h"


/// @file Configuration.h
/// @brief parses xml config file
/// @author Perseedoss Rajiv
/// @version 1.0
/// @date 29.03.11
/// Revision History :
/// Initial Version 29.03.11
/// @class Configuration
/// @brief static class that deals with reading of xml configuration file and initialisations

class Configuration
{
public:
    /// @brief debug parameter used in all the files to enable debugging and console output
    static bool s_debug;

    /// @brief acceleration due to gravity(free fall) value
    static ngl::Real s_accelerationOfFreeFall;

    /// @brief particle default colour
    static ngl::Colour s_normalColour;

    /// @brief boundary colour
    static ngl::Colour s_boundaryColour;

    /// @brief global unique id available for creation of next particle in a fluid
    static int s_nextParticleId;

    /// @brief global unique id available for creation of next obstacle
    static int s_nextObstacleId;

public :
    /// @brief set global parameters from the config file
    /// @param[out] o_frameRate the frame rate for the simulation
    /// @param[out] o_mouseMoveSensitivity sensitivity value of the mouse (x,y) movement
    /// @param[out] o_timestep global timestep of simulation
    /// @param[out] o_fpsTimerEnabled global timestep of simulation
    /// @param[out] o_cacheEnabled flag to toggle cache
    /// @param[out] o_cacheSamplingInterval cache sampling interval
    /// @param[out] o_cacheAutomaticFlushEnabled flag to toggle automatic flush
    /// @param[out] o_cacheAutomaticFlushInterval automatic flush interval
    /// @param[out] o_cacheExportRBDEnabled flag to toggle cache of rbd
    /// @param[out] o_cacheExportBoundaryEnabled flag to toggle cache of boundary
    /// @param[out] o_path global timestep of simulation
    static void initialiseWindow
                            (
                                int& o_frameRate,
                                int& o_mouseMoveSensitivity,
                                ngl::Real& o_timestep,
                                bool& o_fpsTimerEnabled,
                                bool& o_cacheEnabled,
                                int& o_cacheSamplingInterval,
                                bool& o_cacheAutomaticFlushEnabled,
                                int& o_cacheAutomaticFlushInterval,
                                bool& o_cacheExportRBDEnabled,
                                bool& o_cacheExportBoundaryEnabled,
                                std::string& o_path
                            );

    /// @brief create and return a camera from config file parameters
    /// @param[in] _aspect the aspect ratio to be used for the camera creation
    static ngl::Camera initialiseCamera(const float _aspect);

    /// @brief create and return a light source from config file parameters
    static ngl::Light initialiseLight();

    /// @brief create and return the list of shaders from config file parameters
    static std::vector<ShaderObject*>* initialiseShader();

    /// @brief initialise environment
    /// @param[out] o_obstacleEnabled flag to toggle rbd
    /// @param[out] o_boundaryPosition boundary position
    /// @param[out] o_boundaryDimension boundary size
    /// @param[out] o_boundaryRestitutionCoefficientForFluid boundary-fluid restitution
    /// @param[out] o_boundaryRestitutionCoefficientForRBD boundary-rbd restitution
    /// @param[out] o_boundaryBoundTop flag to enable top face bounding
    /// @param[out] o_sphereObstacleList list of sphere rbd
    /// @param[out] o_capsuleObstacleList list of capsule rbd
    /// @param[out] o_obstacleRestitutionCoefficient rbd-fluid restitution
    /// @param[out] o_periodicWallEnabled flag to toggle periodic wall
    /// @param[out] o_periodicWallMaxAmplitude maximum amplitude of periodic wall
    /// @param[out] o_periodicWallSpeed speed factor of periodic wall
    /// @param[out] o_periodicWallAngleIncrement angle increment of periodic wall
    /// @param[out] o_capsuleResolution capsule resolution of drawing
    static void initialiseEnvironment
                            (
                                bool &o_obstacleEnabled,
                                ngl::Vector &o_boundaryPosition,
                                ngl::Vector &o_boundaryDimension,
                                ngl::Real& o_boundaryRestitutionCoefficientForFluid,
                                ngl::Real& o_boundaryRestitutionCoefficientForRBD,
                                bool& o_boundaryBoundTop,
                                std::vector<Particle>& o_sphereObstacleList,
                                std::vector<Capsule>& o_capsuleObstacleList,
                                ngl::Real& o_obstacleRestitutionCoefficient,
                                bool& o_periodicWallEnabled,
                                ngl::Real& o_periodicWallMaxAmplitude,
                                ngl::Real& o_periodicWallSpeed,
                                ngl::Real& o_periodicWallAngleIncrement,
                                int& o_capsuleResolution
                            );

    /// @brief initialise solver
    /// @param[out] o_smoothingLength smoothing length of neighbour structure
    /// @param[out] o_particleList fluid particle list
    /// @param[out] o_hoseParticlePrototypeList list of sample particles for each fluid
    /// @param[out] o_hoseParticleList hose particles
    /// @param[out] o_centerOfHose centre position of hose
    /// @param[out] o_velocityOfHose velocity of hose
    /// @param[out] o_drawHoseMarker flag to toggle whether to draw hose marker
    /// @param[out] o_hoseWaitUntilFirstHitBoundary flag to toggle whether hose particles hit boundary first to start behaving as fluids
    /// @param[out] o_hoseWaitUntilFirstHitRBD flag to toggle whether hose particles hit RBD first to start behaving as fluids
    static void initialiseFluidSolver
            (
                ngl::Real& o_smoothingLength,
                std::vector<FluidParticle>& o_particleList,
                std::vector<FluidParticle>& o_hoseParticlePrototypeList,
                std::vector<FluidParticle>& o_hoseParticleList,
                ngl::Vector& o_centerOfHose,
                ngl::Vector& o_velocityOfHose,
                bool& o_drawHoseMarker,
                bool& o_hoseWaitUntilFirstHitBoundary,
                bool& o_hoseWaitUntilFirstHitRBD
            );



private:
    /// @brief the path of the configuration xml file
    static std::string s_settingsDoc;

private:
    /// @brief utility function to split a string into a vector of floats
    /// @param[in] _str the input string to be split
    /// @param[in] _d the count of split parts to be used as the size of the vector
    static std::vector<ngl::Real> getFloatVectorFromString
                                            (
                                                const std::string _str,
                                                const int _d
                                            );


};

#endif // CONFIGURATION_H
